ax88179_178a USB 3.0 Ethernet


diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 1c4aee4..fdcd0bb 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -157,6 +157,24 @@ config USB_NET_AX8817X
 	  This driver creates an interface named "ethX", where X depends on
 	  what other networking devices you have in use.
 
+config USB_NET_AX88179_178A
+        tristate "ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet"
+        depends on USB_USBNET
+        select CRC32
+#        select PHYLIB
+        default y
+        help
+          This option adds support for ASIX AX88179 based USB 3.0/2.0
+          to Gigabit Ethernet adapters.
+
+          This driver should work with at least the following devices:
+            * ASIX AX88179
+            * ASIX AX88178A
+            * Sitcomm LN-032
+
+          This driver creates an interface named "ethX", where X depends on
+          what other networking devices you have in use.
+
 config USB_NET_QF9700
 	tristate "QF9700 Based USB 2.0 Ethernet Adapters"
 	depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index e307868..6f9dd39 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB_PEGASUS)	+= pegasus.o
 obj-$(CONFIG_USB_RTL8150)	+= rtl8150.o
 obj-$(CONFIG_USB_HSO)		+= hso.o
 obj-$(CONFIG_USB_NET_AX8817X)	+= asix.o
+obj-$(CONFIG_USB_NET_AX88179_178A)	+= ax88179_178a.o
 obj-$(CONFIG_USB_NET_QF9700)	+= qf9700.o
 obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o
 obj-$(CONFIG_USB_NET_CDC_EEM)	+= cdc_eem.o
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
new file mode 100644
index 0000000..1c1a14f
--- /dev/null
+++ b/drivers/net/usb/ax88179_178a.c
@@ -0,0 +1,2173 @@
+/*
+ * ASIX AX88179 based USB 3.0 Ethernet Devices
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
+ * Copyright (c) 2002-2003 TiVo Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* debug messages, extra info */
+/* #define	DEBUG */
+
+#include <linux/version.h>
+/*#include <linux/config.h>*/
+#ifdef	CONFIG_USB_DEBUG
+#define DEBUG
+#endif
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/if_vlan.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
+#include <linux/usb/usbnet.h>
+#else
+#include <../drivers/usb/net/usbnet.h>
+#endif
+
+#include "ax88179_178a.h"
+
+#define DRV_VERSION	"1.14.2"
+
+static char version[] =
+KERN_INFO "ASIX USB Ethernet Adapter:v" DRV_VERSION
+//	" " __TIME__ " " __DATE__ "\n"
+"		http://www.asix.com.tw\n";
+
+static int msg_enable;
+module_param(msg_enable, int, 0);
+MODULE_PARM_DESC(msg_enable, "usbnet msg_enable");
+
+static int bsize = -1;
+module_param(bsize, int, 0);
+MODULE_PARM_DESC(bsize, "RX Bulk IN Queue Size");
+
+static int ifg = -1;
+module_param(ifg, int, 0);
+MODULE_PARM_DESC(ifg, "RX Bulk IN Inter Frame Gap");
+
+
+/* EEE advertisement is disabled in default setting */
+static int bEEE = 0;
+module_param(bEEE, int, 0);
+MODULE_PARM_DESC(bEEE, "EEE advertisement configuration");
+
+/* Green ethernet advertisement is disabled in default setting */
+static int bGETH = 0;
+module_param(bGETH, int, 0);
+MODULE_PARM_DESC(bGETH, "Green ethernet configuration");
+/* ASIX AX88179/178A based USB 3.0/2.0 Gigabit Ethernet Devices */
+
+static int __ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+			      u16 size, void *data, int in_pm)
+{
+	int ret;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+	int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16);
+
+	BUG_ON(!dev);
+
+	if (!in_pm)
+		fn = usbnet_read_cmd;
+	else
+		fn = usbnet_read_cmd_nopm;
+
+	ret = fn(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR |
+		 USB_RECIP_DEVICE, value, index, data, size);
+
+	if (unlikely(ret < 0))
+		netdev_warn(dev->net, "Failed to read reg index 0x%04x: %d\n",
+			    index, ret);
+#else
+	ret = usb_control_msg(
+		dev->udev,
+		usb_rcvctrlpipe(dev->udev, 0),
+		cmd,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		value,
+		index,
+		data,
+		size,
+		USB_CTRL_GET_TIMEOUT);
+#endif
+	return ret;
+}
+
+static int __ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+			       u16 size, void *data, int in_pm)
+{
+	int ret;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+	int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16);
+
+	BUG_ON(!dev);
+
+	if (!in_pm)
+		fn = usbnet_write_cmd;
+	else
+		fn = usbnet_write_cmd_nopm;
+
+	ret = fn(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR |
+		 USB_RECIP_DEVICE, value, index, data, size);
+
+	if (unlikely(ret < 0))
+		netdev_warn(dev->net, "Failed to write reg index 0x%04x: %d\n",
+			    index, ret);
+#else
+	ret = usb_control_msg(
+		dev->udev,
+		usb_sndctrlpipe(dev->udev, 0),
+		cmd,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		value,
+		index,
+		data,
+		size,
+		USB_CTRL_SET_TIMEOUT);
+
+#endif
+	return ret;
+}
+
+static int ax88179_read_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value,
+				 u16 index, u16 size, void *data, int eflag)
+{
+	int ret;
+
+	if (eflag && (2 == size)) {
+		u16 buf = 0;
+		ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 1);
+		le16_to_cpus(&buf);
+		*((u16 *)data) = buf;
+	} else if (eflag && (4 == size)) {
+		u32 buf = 0;
+		ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 1);
+		le32_to_cpus(&buf);
+		*((u32 *)data) = buf;
+	} else {
+		ret = __ax88179_read_cmd(dev, cmd, value, index, size, data, 1);
+	}
+
+	return ret;
+}
+
+static int ax88179_write_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value,
+				  u16 index, u16 size, void *data)
+{
+	int ret;
+
+	if (2 == size) {
+		u16 buf = 0;
+		buf = *((u16 *)data);
+		cpu_to_le16s(&buf);
+		ret = __ax88179_write_cmd(dev, cmd, value, index,
+					  size, &buf, 1);
+	} else {
+		ret = __ax88179_write_cmd(dev, cmd, value, index,
+					  size, data, 1);
+	}
+
+	return ret;
+}
+
+static int ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+			    u16 size, void *data, int eflag)
+{
+
+	int ret;
+
+	if (eflag && (2 == size)) {
+		u16 buf = 0;
+		ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0);
+		le16_to_cpus(&buf);
+		*((u16 *)data) = buf;
+	} else if (eflag && (4 == size)) {
+		u32 buf = 0;
+		ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0);
+		le32_to_cpus(&buf);
+		*((u32 *)data) = buf;
+	} else {
+		ret = __ax88179_read_cmd(dev, cmd, value, index, size, data, 0);
+	}
+
+	return ret;
+}
+
+static int ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+			     u16 size, void *data)
+{
+	int ret;
+
+	if (2 == size) {
+		u16 buf = 0;
+		buf = *((u16 *)data);
+		cpu_to_le16s(&buf);
+		ret = __ax88179_write_cmd(dev, cmd, value, index,
+					  size, &buf, 0);
+	} else {
+		ret = __ax88179_write_cmd(dev, cmd, value, index,
+					  size, data, 0);
+	}
+
+	return ret;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void ax88179_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
+#else
+static void ax88179_async_cmd_callback(struct urb *urb)
+#endif
+{
+	struct ax88179_async_handle *asyncdata = (struct ax88179_async_handle *)urb->context;
+
+	if (urb->status < 0)
+		printk(KERN_ERR "ax88179_async_cmd_callback() failed with %d",
+		       urb->status);
+
+	kfree(asyncdata->req);
+	kfree(asyncdata);	
+	usb_free_urb(urb);
+	
+}
+
+static void
+ax88179_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+				    u16 size, void *data)
+{
+	struct usb_ctrlrequest *req = NULL;
+	int status = 0;
+	struct urb *urb = NULL;
+	void *buf = NULL;
+	struct ax88179_async_handle *asyncdata = NULL;
+
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (urb == NULL) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_err(dev->net, "Error allocating URB in write_cmd_async!");
+#else
+		deverr(dev, "Error allocating URB in write_cmd_async!");
+#endif
+		return;
+	}
+
+	req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
+	if (req == NULL) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_err(dev->net, "Failed to allocate memory for control request");
+#else
+		deverr(dev, "Failed to allocate memory for control request");
+#endif
+		usb_free_urb(urb);
+		return;
+	}
+
+	asyncdata = (struct ax88179_async_handle*)
+			kmalloc(sizeof(struct ax88179_async_handle), GFP_ATOMIC);
+	if (asyncdata == NULL) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_err(dev->net, "Failed to allocate memory for async data");
+#else
+		deverr(dev, "Failed to allocate memory for async data");
+#endif
+		kfree(req);
+		usb_free_urb(urb);
+		return;
+	}
+
+	asyncdata->req = req;
+	
+	if (size == 2) {
+		asyncdata->rxctl = *((u16 *)data);
+		cpu_to_le16s(&asyncdata->rxctl);
+		buf = &asyncdata->rxctl;
+	} else {
+		memcpy(asyncdata->m_filter, data, size);
+		buf = asyncdata->m_filter;
+	}
+
+	req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+	req->bRequest = cmd;
+	req->wValue = cpu_to_le16(value);
+	req->wIndex = cpu_to_le16(index);
+	req->wLength = cpu_to_le16(size);
+
+	usb_fill_control_urb(urb, dev->udev,
+			     usb_sndctrlpipe(dev->udev, 0),
+			     (void *)req, buf, size,
+			     ax88179_async_cmd_callback, asyncdata);
+
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status < 0) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_err(dev->net, "Error submitting the control message: status=%d",
+			   status);
+#else
+		deverr(dev, "Error submitting the control message: status=%d",
+		       status);
+#endif
+		kfree(req);
+		kfree(asyncdata);
+		usb_free_urb(urb);
+	}
+}
+
+static void ax88179_status(struct usbnet *dev, struct urb *urb)
+{
+	struct ax88179_int_data *event = NULL;
+	int link = 0;
+
+	if (urb->actual_length < 8)
+		return;
+
+	event = urb->transfer_buffer;
+	link = event->link & AX_INT_PPLS_LINK;
+
+	if (netif_carrier_ok(dev->net) != link) {
+		if (link) {
+			netif_carrier_on(dev->net);
+			usbnet_defer_kevent(dev, EVENT_LINK_RESET);
+		}
+		else
+			netif_carrier_off(dev->net);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_info(dev->net, "ax88179_178a - Link status is: %d\n",
+			    link);
+#else
+		devinfo(dev, "ax88179_178a - Link status is: %d\n", link);
+#endif
+	}
+}
+
+static int ax88179_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	u16 res = 0;
+
+	ax88179_read_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res, 1);
+	return res;
+}
+
+static void ax88179_mdio_write(struct net_device *netdev, int phy_id, int loc,
+			       int val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	u16 res = (u16)val;
+
+	ax88179_write_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res);
+}
+
+static int ax88179_suspend(struct usb_interface *intf,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10)
+			   pm_message_t message)
+#else
+			   u32 message)
+#endif
+{
+	struct usbnet *dev = usb_get_intfdata(intf);
+	u16 tmp16 = 0;
+	u8 tmp8 = 0;
+
+	usbnet_suspend(intf, message);
+
+	/* Disable RX path */
+	ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+			      2, 2, &tmp16, 1);
+	tmp16 &= ~AX_MEDIUM_RECEIVE_EN;
+	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC,  AX_MEDIUM_STATUS_MODE,
+			       2, 2, &tmp16);
+
+	/* Force bz */
+	ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
+			      2, 2, &tmp16, 1);
+	tmp16 |= AX_PHYPWR_RSTCTL_BZ | AX_PHYPWR_RSTCTL_IPRL;
+	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
+			       2, 2, &tmp16);
+
+	/* change clock */
+	tmp8 = 0;
+	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8);
+
+	/* Configure RX control register => stop operation */
+	tmp16 = AX_RX_CTL_STOP;
+	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16);
+
+	return 0;
+}
+
+
+static void ax88179_EEE_setting(struct usbnet *dev)
+{
+	u16 tmp16;
+	
+	if (bEEE) {
+		// Enable EEE
+		tmp16 = 0x07;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  GMII_PHY_MACR, 2, &tmp16);
+
+		tmp16 = 0x3c;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  GMII_PHY_MAADR, 2, &tmp16);
+
+		tmp16 = 0x4007;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  GMII_PHY_MACR, 2, &tmp16);
+
+		tmp16 = 0x06;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  GMII_PHY_MAADR, 2, &tmp16);
+	} else {
+		// Disable EEE
+		tmp16 = 0x07;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  GMII_PHY_MACR, 2, &tmp16);
+
+		tmp16 = 0x3c;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  GMII_PHY_MAADR, 2, &tmp16);
+
+		tmp16 = 0x4007;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  GMII_PHY_MACR, 2, &tmp16);
+
+		tmp16 = 0x00;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  GMII_PHY_MAADR, 2, &tmp16);
+	}
+}
+
+static void ax88179_Gether_setting(struct usbnet *dev)
+{
+
+	u16 tmp16;
+
+	if (bGETH) {
+		// Enable Green Ethernet
+		tmp16 = 0x03;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  31, 2, &tmp16);
+
+		tmp16 = 0x3247;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  25, 2, &tmp16);
+
+		tmp16 = 0x05;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  31, 2, &tmp16);
+
+		tmp16 = 0x0680;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  1, 2, &tmp16);
+
+		tmp16 = 0;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  31, 2, &tmp16);
+	} else {
+		// Disable Green Ethernet
+		tmp16 = 0x03;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  31, 2, &tmp16);
+
+		tmp16 = 0x3246;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  25, 2, &tmp16);
+
+		tmp16 = 0;
+		ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+				  31, 2, &tmp16);
+	}
+}
+
+static int ax88179_resume(struct usb_interface *intf)
+{
+	struct usbnet *dev = usb_get_intfdata(intf);
+	u16 tmp16 = 0;
+	u8 tmp8 = 0;
+
+	netif_carrier_off(dev->net);
+
+	/* Power up ethernet PHY */
+	tmp16 = 0;
+	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
+			       2, 2, &tmp16);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
+	usleep_range(1000, 2000);
+#else
+	msleep(1);
+#endif
+	tmp16 = AX_PHYPWR_RSTCTL_IPRL;
+	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
+			       2, 2, &tmp16);
+	msleep(200);
+
+	/* Ethernet PHY Auto Detach*/
+	ax88179_AutoDetach(dev, 1);
+
+	/* change clock */
+	ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC,  AX_CLK_SELECT,
+			      1, 1, &tmp8, 0);
+	tmp8 |= AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
+	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8);
+	msleep(100);
+
+	/* Configure RX control register => start operation */
+	tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_START | AX_RX_CTL_AP |
+		 AX_RX_CTL_AMALL | AX_RX_CTL_AB;
+	if (NET_IP_ALIGN == 0)
+		tmp16 |= AX_RX_CTL_IPE;
+	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16);
+
+	return usbnet_resume(intf);
+}
+
+static void
+ax88179_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+{
+
+	struct usbnet *dev = netdev_priv(net);
+	u8 *opt = NULL;
+
+	opt = kmalloc(1, GFP_KERNEL);
+	if (!opt)
+		return;
+
+	if (ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE,
+			     1, 1, opt, 0) < 0) {
+		wolinfo->supported = 0;
+		wolinfo->wolopts = 0;
+		kfree(opt);
+		return;
+	}
+
+	wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
+
+	if (*opt & AX_MONITOR_MODE_RWLC)
+		wolinfo->wolopts |= WAKE_PHY;
+	if (*opt & AX_MONITOR_MODE_RWMP)
+		wolinfo->wolopts |= WAKE_MAGIC;
+
+	kfree(opt);
+}
+
+static int
+ax88179_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+{
+	struct usbnet *dev = netdev_priv(net);
+	u8 *opt = NULL;
+
+	opt = kmalloc(1, GFP_KERNEL);
+	if (!opt)
+		return -ENOMEM;
+
+	*opt = 0;
+
+	if (wolinfo->wolopts & WAKE_PHY)
+		*opt |= AX_MONITOR_MODE_RWLC;
+	else
+		*opt &= ~AX_MONITOR_MODE_RWLC;
+
+	if (wolinfo->wolopts & WAKE_MAGIC)
+		*opt |= AX_MONITOR_MODE_RWMP;
+	else
+		*opt &= ~AX_MONITOR_MODE_RWMP;
+
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, opt);
+
+	kfree(opt);
+
+	return 0;
+}
+
+static int ax88179_get_eeprom_len(struct net_device *net)
+{
+	return AX_EEPROM_LEN;
+}
+
+static int
+ax88179_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
+		   u8 *data)
+{
+	struct usbnet *dev = netdev_priv(net);
+	u16 *eeprom_buff = NULL;
+	int first_word = 0, last_word = 0;
+	int i = 0;
+
+	if (eeprom->len == 0)
+		return -EINVAL;
+
+	eeprom->magic = AX88179_EEPROM_MAGIC;
+
+	first_word = eeprom->offset >> 1;
+	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+	eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1),
+			      GFP_KERNEL);
+	if (!eeprom_buff)
+		return -ENOMEM;
+
+	/* ax88179/178A returns 2 bytes from eeprom on read */
+	for (i = first_word; i <= last_word; i++) {
+		if (ax88179_read_cmd(dev, AX_ACCESS_EEPROM, i, 1, 2,
+				     &(eeprom_buff[i - first_word]), 0) < 0) {
+			kfree(eeprom_buff);
+			return -EIO;
+		}
+	}
+
+	memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
+	kfree(eeprom_buff);
+	return 0;
+}
+
+static void ax88179_get_drvinfo(struct net_device *net,
+				struct ethtool_drvinfo *info)
+{
+	/* Inherit standard device info */
+	usbnet_get_drvinfo(net, info);
+	info->eedump_len = 0x3e;
+}
+
+static int ax88179_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+	return mii_ethtool_gset(&dev->mii, cmd);
+}
+
+static int ax88179_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+	return mii_ethtool_sset(&dev->mii, cmd);
+}
+
+static int ax88179_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+	return  generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 28)
+static int ax88179_netdev_stop(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	u16 tmp16 = 0;
+
+	ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+			 2, 2, &tmp16, 1);
+	tmp16 &= ~AX_MEDIUM_RECEIVE_EN;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+			  2, 2, &tmp16);
+	return 0;
+}
+#endif
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
+static int ax88179_set_csums(struct usbnet *dev)
+{
+	struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
+	u8 checksum = 0;
+
+	if (ax179_data->checksum & AX_RX_CHECKSUM)
+		checksum = AX_RXCOE_DEF_CSUM;
+	else
+		checksum = 0;
+
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, &checksum);
+
+	if (ax179_data->checksum & AX_TX_CHECKSUM)
+		checksum = AX_TXCOE_DEF_CSUM;
+	else
+		checksum = 0;
+
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &checksum);
+
+	return 0;
+}
+
+static u32 ax88179_get_tx_csum(struct net_device *netdev)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
+	return ax179_data->checksum & AX_TX_CHECKSUM;
+}
+
+static u32 ax88179_get_rx_csum(struct net_device *netdev)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
+	return ax179_data->checksum & AX_RX_CHECKSUM;
+}
+
+static int ax88179_set_rx_csum(struct net_device *netdev, u32 val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
+
+	if (val)
+		ax179_data->checksum |= AX_RX_CHECKSUM;
+	else
+		ax179_data->checksum &= ~AX_RX_CHECKSUM;
+	return ax88179_set_csums(dev);
+}
+
+static int ax88179_set_tx_csum(struct net_device *netdev, u32 val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
+
+	if (val)
+		ax179_data->checksum |= AX_TX_CHECKSUM;
+	else
+		ax179_data->checksum &= ~AX_TX_CHECKSUM;
+
+	ethtool_op_set_tx_csum(netdev, val);
+
+	return ax88179_set_csums(dev);
+}
+
+static int ax88179_set_tso(struct net_device *netdev, u32 data)
+{
+	if (data)
+		netdev->features |= NETIF_F_TSO;
+	else
+		netdev->features &= ~NETIF_F_TSO;
+
+	return 0;
+}
+#endif
+
+static struct ethtool_ops ax88179_ethtool_ops = {
+	.get_drvinfo		= ax88179_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+	.get_msglevel		= usbnet_get_msglevel,
+	.set_msglevel		= usbnet_set_msglevel,
+	.get_wol		= ax88179_get_wol,
+	.set_wol		= ax88179_set_wol,
+	.get_eeprom_len		= ax88179_get_eeprom_len,
+	.get_eeprom		= ax88179_get_eeprom,
+	.get_settings		= ax88179_get_settings,
+	.set_settings		= ax88179_set_settings,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
+	.set_tx_csum		= ax88179_set_tx_csum,
+	.get_tx_csum		= ax88179_get_tx_csum,
+	.get_rx_csum		= ax88179_get_rx_csum,
+	.set_rx_csum		= ax88179_set_rx_csum,
+	.get_tso		= ethtool_op_get_tso,
+	.set_tso		= ax88179_set_tso,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= ethtool_op_set_sg
+#endif
+};
+
+static void ax88179_set_multicast(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	struct ax88179_data *data = (struct ax88179_data *)&dev->data;
+	u8 *m_filter = ((u8 *)dev->data) + 12;
+	int mc_count = 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+	mc_count = net->mc_count;
+#else
+	mc_count = netdev_mc_count(net);
+#endif
+
+	data->rxctl = (AX_RX_CTL_START | AX_RX_CTL_AB);
+	if (NET_IP_ALIGN == 0)
+		data->rxctl |= AX_RX_CTL_IPE;
+
+	if (net->flags & IFF_PROMISC) {
+		data->rxctl |= AX_RX_CTL_PRO;
+	} else if (net->flags & IFF_ALLMULTI
+		   || mc_count > AX_MAX_MCAST) {
+		data->rxctl |= AX_RX_CTL_AMALL;
+	} else if (mc_count == 0) {
+		/* just broadcast and directed */
+	} else {
+		/* We use the 20 byte dev->data
+		 * for our 8 byte filter buffer
+		 * to avoid allocating memory that
+		 * is tricky to free later */
+		u32 crc_bits = 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+		struct dev_mc_list *mc_list = net->mc_list;
+		int i = 0;
+
+		memset(m_filter, 0, AX_MCAST_FILTER_SIZE);
+
+		/* Build the multicast hash filter. */
+		for (i = 0; i < net->mc_count; i++) {
+			crc_bits =
+			    ether_crc(ETH_ALEN,
+				      mc_list->dmi_addr) >> 26;
+			*(m_filter + (crc_bits >> 3)) |=
+				1 << (crc_bits & 7);
+			mc_list = mc_list->next;
+		}
+#else
+		struct netdev_hw_addr *ha = NULL;
+		memset(m_filter, 0, AX_MCAST_FILTER_SIZE);
+		netdev_for_each_mc_addr(ha, net) {
+			crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
+			*(m_filter + (crc_bits >> 3)) |=
+				1 << (crc_bits & 7);
+		}
+#endif
+		ax88179_write_cmd_async(dev, AX_ACCESS_MAC,
+					AX_MULTI_FILTER_ARRY,
+					AX_MCAST_FILTER_SIZE,
+					AX_MCAST_FILTER_SIZE, m_filter);
+
+		data->rxctl |= AX_RX_CTL_AM;
+	}
+
+	ax88179_write_cmd_async(dev, AX_ACCESS_MAC, AX_RX_CTL,
+				2, 2, &data->rxctl);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+static int
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+ax88179_set_features(struct net_device *net, netdev_features_t features)
+#else
+ax88179_set_features(struct net_device *net, u32 features)
+#endif
+
+{
+	u8 tmp = 0;
+	struct usbnet *dev = netdev_priv(net);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+	netdev_features_t changed = net->features ^ features;
+#else
+	u32 changed = net->features ^ features;
+#endif
+
+	if (changed & NETIF_F_IP_CSUM) {
+		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL,
+				 1, 1, &tmp, 0);
+		tmp ^= AX_TXCOE_TCP | AX_TXCOE_UDP;
+		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp);
+	}
+
+	if (changed & NETIF_F_IPV6_CSUM) {
+		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL,
+				 1, 1, &tmp, 0);
+		tmp ^= AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
+		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp);
+	}
+
+	if (changed & NETIF_F_RXCSUM) {
+		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL,
+				 1, 1, &tmp, 0);
+		tmp ^= AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
+		       AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
+		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, &tmp);
+	}
+
+	return 0;
+}
+#endif
+
+static int ax88179_change_mtu(struct net_device *net, int new_mtu)
+{
+	struct usbnet *dev = netdev_priv(net);
+	u16 tmp16 = 0;
+
+	if (new_mtu <= 0 || new_mtu > 4088)
+		return -EINVAL;
+
+	net->mtu = new_mtu;
+	dev->hard_mtu = net->mtu + net->hard_header_len;
+
+	if (net->mtu > 1500) {
+		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+				 2, 2, &tmp16, 1);
+		tmp16 |= AX_MEDIUM_JUMBO_EN;
+		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+				  2, 2, &tmp16);
+	} else {
+		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+				 2, 2, &tmp16, 1);
+		tmp16 &= ~AX_MEDIUM_JUMBO_EN;
+		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+				  2, 2, &tmp16);
+	}
+
+	return 0;
+}
+
+static int ax88179_set_mac_addr(struct net_device *net, void *p)
+{
+	struct usbnet *dev = netdev_priv(net);
+	struct sockaddr *addr = p;
+
+	if (netif_running(net))
+		return -EBUSY;
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);
+
+	/* Set the MAC address */
+	return ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
+				 ETH_ALEN, net->dev_addr);
+
+}
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+static const struct net_device_ops ax88179_netdev_ops = {
+	.ndo_open		= usbnet_open,
+	.ndo_stop		= usbnet_stop,
+	.ndo_start_xmit		= usbnet_start_xmit,
+	.ndo_tx_timeout		= usbnet_tx_timeout,
+	.ndo_change_mtu		= ax88179_change_mtu,
+	.ndo_do_ioctl		= ax88179_ioctl,
+	.ndo_set_mac_address	= ax88179_set_mac_addr,
+	.ndo_validate_addr	= eth_validate_addr,
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 2, 0)
+	.ndo_set_multicast_list	= ax88179_set_multicast,
+#else
+	.ndo_set_rx_mode	= ax88179_set_multicast,
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+	.ndo_set_features	= ax88179_set_features,
+#endif
+};
+#endif
+
+static int ax88179_check_eeprom(struct usbnet *dev)
+{
+	u8 i = 0;
+	u8 buf[2] = {0};
+	u8 eeprom[20] = {0};
+	u16 csum = 0, delay = HZ / 10;
+	unsigned long jtimeout = 0;
+
+	/* Read EEPROM content */
+	for (i = 0 ; i < 6; i++) {
+
+		buf[0] = i;
+		if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_ADDR,
+				      1, 1, buf) < 0)
+			return -EINVAL;
+
+		buf[0] = EEP_RD;
+		if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
+				      1, 1, buf) < 0)
+			return -EINVAL;
+
+		jtimeout = jiffies + delay;
+		do {
+			ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
+					 1, 1, buf, 0);
+
+			if (time_after(jiffies, jtimeout))
+				return -EINVAL;
+		} while (buf[0] & EEP_BUSY);
+
+		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_LOW,
+				 2, 2, &eeprom[i * 2], 0);
+
+		if ((i == 0) && (eeprom[0] == 0xFF))
+			return -EINVAL;
+	}
+
+	csum = eeprom[6] + eeprom[7] + eeprom[8] + eeprom[9];
+	csum = (csum >> 8) + (csum & 0xff);
+
+	if ((csum + eeprom[10]) == 0xff)
+		return AX_EEP_EFUSE_CORRECT;
+	else
+		return -EINVAL;
+}
+
+static int ax88179_check_efuse(struct usbnet *dev, void *ledmode)
+{
+	u8	i = 0;
+	u8	efuse[64] = {0x00};
+	u16	csum = 0;
+
+	if (ax88179_read_cmd(dev, AX_ACCESS_EFUSE, 0, 64, 64, efuse, 0) < 0)
+		return -EINVAL;
+
+	if (efuse[0] == 0xFF)
+		return -EINVAL;
+
+	for (i = 0; i < 64; i++)
+		csum = csum + efuse[i];
+
+	while (csum > 255)
+		csum = (csum & 0x00FF) + ((csum >> 8) & 0x00FF);
+
+	if (csum == 0xFF) {
+		memcpy((u8 *)ledmode, &efuse[51], 2);
+		return AX_EEP_EFUSE_CORRECT;
+	} else {
+		return -EINVAL;
+	}
+}
+
+static int ax88179_convert_old_led(struct usbnet *dev, u8 efuse, void *ledvalue)
+{
+	u8 ledmode = 0;
+	u16 tmp = 0;
+	u16 led = 0;
+
+	/* loaded the old eFuse LED Mode */
+	if (efuse) {
+		if (ax88179_read_cmd(dev, AX_ACCESS_EFUSE, 0x18,
+				     1, 2, &tmp, 1) < 0)
+			return -EINVAL;
+		ledmode = (u8)(tmp & 0xFF);
+	} else { /* loaded the old EEprom LED Mode */
+		if (ax88179_read_cmd(dev, AX_ACCESS_EEPROM, 0x3C,
+				     1, 2, &tmp, 1) < 0)
+			return -EINVAL;
+		ledmode = (u8) (tmp >> 8);
+	}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+	netdev_dbg(dev->net, "Old LED Mode = %02X\n", ledmode);
+#else
+	devdbg(dev, "Old LED Mode = %02X\n", ledmode);
+#endif
+	switch (ledmode) {
+	case 0xFF:
+		led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 |
+		      LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 |
+		      LED2_LINK_100 | LED2_LINK_1000 | LED_VALID;
+		break;
+	case 0xFE:
+		led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 | LED_VALID;
+		break;
+	case 0xFD:
+		led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 |
+		      LED2_LINK_10 | LED_VALID;
+		break;
+	case 0xFC:
+		led = LED0_ACTIVE | LED1_ACTIVE | LED1_LINK_1000 | LED2_ACTIVE |
+		      LED2_LINK_100 | LED2_LINK_10 | LED_VALID;
+		break;
+	default:
+		led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 |
+		      LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 |
+		      LED2_LINK_100 | LED2_LINK_1000 | LED_VALID;
+		break;
+	}
+
+	memcpy((u8 *)ledvalue, &led, 2);
+
+	return 0;
+}
+
+static int ax88179_led_setting(struct usbnet *dev)
+{
+	u8 ledfd = 0, value = 0;
+	u16 tmp = 0, ledact = 0, ledlink = 0, ledvalue = 0, delay = HZ / 10;
+	unsigned long jtimeout = 0;
+
+	/* Check AX88179 version. UA1 or UA2 */
+	ax88179_read_cmd(dev, AX_ACCESS_MAC, GENERAL_STATUS, 1, 1, &value, 0);
+
+	/* UA1 */
+	if (!(value & AX_SECLD)) {
+		value = AX_GPIO_CTRL_GPIO3EN | AX_GPIO_CTRL_GPIO2EN |
+			AX_GPIO_CTRL_GPIO1EN;
+		if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_GPIO_CTRL,
+				      1, 1, &value) < 0)
+			return -EINVAL;
+	}
+
+	/* check EEprom */
+	if (ax88179_check_eeprom(dev) == AX_EEP_EFUSE_CORRECT) {
+		value = 0x42;
+		if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_ADDR,
+				      1, 1, &value) < 0)
+			return -EINVAL;
+
+		value = EEP_RD;
+		if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
+				      1, 1, &value) < 0)
+			return -EINVAL;
+
+		jtimeout = jiffies + delay;
+		do {
+			ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
+					 1, 1, &value, 0);
+
+			ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
+					 1, 1, &value, 0);
+
+			if (time_after(jiffies, jtimeout))
+				return -EINVAL;
+		} while (value & EEP_BUSY);
+
+		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_HIGH,
+				 1, 1, &value, 0);
+		ledvalue = (value << 8);
+		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_LOW,
+				 1, 1, &value, 0);
+		ledvalue |= value;
+
+		/* load internal ROM for defaule setting */
+		if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0))
+			ax88179_convert_old_led(dev, 0, &ledvalue);
+
+	} else if (ax88179_check_efuse(dev, &ledvalue) ==
+				       AX_EEP_EFUSE_CORRECT) { /* check efuse */
+		if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0))
+			ax88179_convert_old_led(dev, 0, &ledvalue);
+	} else {
+		ax88179_convert_old_led(dev, 0, &ledvalue);
+	}
+
+	tmp = GMII_PHY_PAGE_SELECT_EXT;
+	ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+			  GMII_PHY_PAGE_SELECT, 2, &tmp);
+
+	tmp = 0x2c;
+	ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+			  GMII_PHYPAGE, 2, &tmp);
+
+	ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+			 GMII_LED_ACTIVE, 2, &ledact, 1);
+
+	ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+			 GMII_LED_LINK, 2, &ledlink, 1);
+
+	ledact &= GMII_LED_ACTIVE_MASK;
+	ledlink &= GMII_LED_LINK_MASK;
+
+	if (ledvalue & LED0_ACTIVE)
+		ledact |= GMII_LED0_ACTIVE;
+	if (ledvalue & LED1_ACTIVE)
+		ledact |= GMII_LED1_ACTIVE;
+	if (ledvalue & LED2_ACTIVE)
+		ledact |= GMII_LED2_ACTIVE;
+
+	if (ledvalue & LED0_LINK_10)
+		ledlink |= GMII_LED0_LINK_10;
+	if (ledvalue & LED1_LINK_10)
+		ledlink |= GMII_LED1_LINK_10;
+	if (ledvalue & LED2_LINK_10)
+		ledlink |= GMII_LED2_LINK_10;
+
+	if (ledvalue & LED0_LINK_100)
+		ledlink |= GMII_LED0_LINK_100;
+	if (ledvalue & LED1_LINK_100)
+		ledlink |= GMII_LED1_LINK_100;
+	if (ledvalue & LED2_LINK_100)
+		ledlink |= GMII_LED2_LINK_100;
+
+	if (ledvalue & LED0_LINK_1000)
+		ledlink |= GMII_LED0_LINK_1000;
+	if (ledvalue & LED1_LINK_1000)
+		ledlink |= GMII_LED1_LINK_1000;
+	if (ledvalue & LED2_LINK_1000)
+		ledlink |= GMII_LED2_LINK_1000;
+
+	tmp = ledact;
+	ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+			  GMII_LED_ACTIVE, 2, &tmp);
+
+	tmp = ledlink;
+	ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+			  GMII_LED_LINK, 2, &tmp);
+
+	tmp = GMII_PHY_PAGE_SELECT_PAGE0;
+	ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+			  GMII_PHY_PAGE_SELECT, 2, &tmp);
+
+	/* LED full duplex setting */
+	ledfd = 0;
+	if (ledvalue & LED0_FD)
+		ledfd |= 0x01;
+	else if ((ledvalue & LED0_USB3_MASK) == 0)
+		ledfd |= 0x02;
+
+
+	if (ledvalue & LED1_FD)
+		ledfd |= 0x04;
+	else if ((ledvalue & LED1_USB3_MASK) == 0)
+		ledfd |= 0x08;
+
+	if (ledvalue & LED2_FD) /* LED2_FD */
+		ledfd |= 0x10;
+	else if ((ledvalue & LED2_USB3_MASK) == 0) /* LED2_USB3 */
+		ledfd |= 0x20;
+
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, 0x73, 1, 1, &ledfd);
+
+	return 0;
+}
+
+static int ax88179_AutoDetach(struct usbnet *dev, int in_pm)
+{
+	u16 tmp16 = 0;
+	u8 tmp8 = 0;
+	int (*fnr)(struct usbnet *, u8, u16, u16, u16, void *, int);
+	int (*fnw)(struct usbnet *, u8, u16, u16, u16, void *);
+
+	if (!in_pm) {
+		fnr = ax88179_read_cmd;
+		fnw = ax88179_write_cmd;
+	} else {
+		fnr = ax88179_read_cmd_nopm;
+		fnw = ax88179_write_cmd_nopm;
+	}
+
+	if (fnr(dev, AX_ACCESS_EEPROM, 0x43, 1, 2, &tmp16, 1) < 0)
+		return 0;
+
+	if ((tmp16 == 0xFFFF) || (!(tmp16 & 0x0100)))
+		return 0;
+
+	/* Enable Auto Detach bit */
+	tmp8 = 0;
+	fnr(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8, 0);
+	tmp8 |= AX_CLK_SELECT_ULR;
+	fnw(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8);
+
+	fnr(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16, 1);
+	tmp16 |= AX_PHYPWR_RSTCTL_AUTODETACH;
+	fnw(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16);
+
+	return 0;
+}
+
+static int access_eeprom_mac(struct usbnet *dev, u8 *buf, u8 offset, bool wflag)
+{
+	int ret = 0, i;
+	u16* tmp = (u16*)buf;
+
+	for (i = 0; i < (ETH_ALEN >> 1); i++) {
+		if (wflag) {
+			u16 wd = cpu_to_le16(*(tmp + i));
+			ret = ax88179_write_cmd(dev, AX_ACCESS_EEPROM,
+						offset + i, 1, 2, &wd);
+			if (ret < 0)
+				break;
+
+			mdelay(15);
+		}
+		else {
+			ret = ax88179_read_cmd(dev, AX_ACCESS_EEPROM,
+						offset + i, 1, 2, tmp + i, 0);
+			if (ret < 0)
+				break;
+		}
+	}
+
+	if (!wflag) {
+		if (ret < 0) {
+			#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+				netdev_dbg(dev->net, "Failed to read MAC address from EEPROM: %d\n", ret);
+			#else
+				devdbg(dev, "Failed to read MAC address from EEPROM: %d\n", ret);
+			#endif
+			return ret;
+		}
+		memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+	}
+	else {
+		/* reload eeprom data */
+		ret = ax88179_write_cmd(dev, AX_RELOAD_EEPROM_EFUSE, 0, 0, 0, 0);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int ax88179_check_ether_addr(struct usbnet *dev)
+{
+	unsigned char *tmp = (unsigned char*)dev->net->dev_addr;
+	u8 default_mac[6] = {0, 0x0e, 0xc6, 0x81, 0x79, 0x01};
+	u8 default_mac_178a[6] = {0, 0x0e, 0xc6, 0x81, 0x78, 0x01};
+
+	if (((*((u8*)tmp) == 0) && (*((u8*)tmp + 1) == 0) && (*((u8*)tmp + 2) == 0)) ||
+	    !is_valid_ether_addr((u8*)tmp) ||
+	    !memcmp(dev->net->dev_addr, default_mac, ETH_ALEN) ||
+	    !memcmp(dev->net->dev_addr, default_mac_178a, ETH_ALEN)) {
+		int i;
+
+		printk("Found invalid EEPROM MAC address value ");
+
+		for (i = 0; i < ETH_ALEN; i++) {
+			printk("%02X", *((u8*)tmp + i));
+			if (i != 5)
+				printk("-");
+		}
+		printk("\n");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+		eth_hw_addr_random(dev->net);
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
+		dev->net->addr_assign_type |= NET_ADDR_RANDOM;
+#endif
+		random_ether_addr(dev->net->dev_addr); 
+#endif
+		*tmp = 0;
+		*(tmp + 1) = 0x0E;
+		*(tmp + 2) = 0xC6;
+		*(tmp + 3) = 0x8E;
+
+		return -EADDRNOTAVAIL;	
+	} 
+	return 0;
+}
+
+static int ax88179_get_mac(struct usbnet *dev, u8* buf)
+{
+	int ret, i;
+
+	ret = access_eeprom_mac(dev, buf, 0x0, 0);
+	if (ret < 0)
+		goto out;
+
+	if (ax88179_check_ether_addr(dev)) {
+		ret = access_eeprom_mac(dev, dev->net->dev_addr, 0x0, 1);
+		if (ret < 0) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_err(dev->net, "Failed to write MAC to EEPROM: %d", ret);
+#else
+		deverr(dev, "Failed to write MAC to EEPROM: %d", ret);
+#endif
+			goto out;
+		}
+
+		msleep(5);
+
+		ret = ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID,
+				       ETH_ALEN, ETH_ALEN, buf, 0);
+		if (ret < 0) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_err(dev->net, "Failed to read MAC address: %d", ret);
+#else
+		deverr(dev, "Failed to read MAC address: %d", ret);
+#endif
+			goto out;
+		}
+
+		for (i = 0; i < ETH_ALEN; i++)
+			if (*(dev->net->dev_addr + i) != *((u8*)buf + i)) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_warn(dev->net, "Found invalid EEPROM part or non-EEPROM");
+#else
+		devwarn(dev, "Found invalid EEPROM part or non-EEPROM");
+#endif
+				break;
+			}
+	}
+
+	memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN);
+
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
+			  ETH_ALEN, dev->net->dev_addr);
+	
+	if (ret < 0) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_err(dev->net, "Failed to write MAC address: %d", ret);
+#else
+		deverr(dev, "Failed to write MAC address: %d", ret);
+#endif
+		goto out;
+	}
+
+	return 0;
+out:
+	return ret;
+}
+
+static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	void *buf = NULL;
+	u16 *tmp16 = NULL;
+	u8 *tmp = NULL;
+	int ret;
+
+	struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
+
+	usbnet_get_endpoints(dev, intf);
+
+	if (msg_enable != 0)
+		dev->msg_enable = msg_enable;
+
+	buf = kmalloc(6, GFP_KERNEL);
+	if (!buf) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_err(dev->net, "Cannot allocate memory for buffer");
+#else
+		deverr(dev, "Cannot allocate memory for buffer");
+#endif
+		return -ENOMEM;
+	}
+	tmp16 = (u16 *)buf;
+	tmp = (u8 *)buf;
+
+	memset(ax179_data, 0, sizeof(*ax179_data));
+
+	/* Power up ethernet PHY */
+	*tmp16 = 0;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
+	*tmp16 = AX_PHYPWR_RSTCTL_IPRL;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
+	msleep(200);
+
+	*tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp);
+	msleep(100);
+
+	/* Get the MAC address */
+	memset(buf, 0, ETH_ALEN);
+	ret = ax88179_get_mac(dev, buf);
+	if (ret)
+		goto out;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_dbg(dev->net, "MAC [%02x-%02x-%02x-%02x-%02x-%02x]\n",
+			   dev->net->dev_addr[0], dev->net->dev_addr[1],
+			   dev->net->dev_addr[2], dev->net->dev_addr[3],
+			   dev->net->dev_addr[4], dev->net->dev_addr[5]);
+#else
+		devdbg(dev, "MAC [%02x-%02x-%02x-%02x-%02x-%02x]\n",
+		       dev->net->dev_addr[0], dev->net->dev_addr[1],
+		       dev->net->dev_addr[2], dev->net->dev_addr[3],
+		       dev->net->dev_addr[4], dev->net->dev_addr[5]);
+#endif
+
+	/* RX bulk configuration, default for USB3.0 to Giga*/
+	memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
+
+	dev->rx_urb_size = 1024 * 20;
+
+	tmp[0] = 0x34;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp);
+
+	tmp[0] = 0x52;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH,
+			  1, 1, tmp);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
+	dev->net->do_ioctl = ax88179_ioctl;
+	dev->net->set_multicast_list = ax88179_set_multicast;
+	dev->net->set_mac_address = ax88179_set_mac_addr;
+	dev->net->change_mtu = ax88179_change_mtu;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 28)
+	dev->net->stop = ax88179_netdev_stop;
+#endif
+#else
+	dev->net->netdev_ops = &ax88179_netdev_ops;
+#endif
+
+	dev->net->ethtool_ops = &ax88179_ethtool_ops;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+	dev->net->needed_headroom = 8;
+#endif
+
+	/* Initialize MII structure */
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = ax88179_mdio_read;
+	dev->mii.mdio_write = ax88179_mdio_write;
+	dev->mii.phy_id_mask = 0xff;
+	dev->mii.reg_num_mask = 0xff;
+	dev->mii.phy_id = 0x03;
+	dev->mii.supports_gmii = 1;
+
+	dev->net->features |= NETIF_F_IP_CSUM;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
+	dev->net->features |= NETIF_F_IPV6_CSUM;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+	if (usb_device_no_sg_constraint(dev->udev))
+		dev->can_dma_sg = 1;
+	dev->net->features |= NETIF_F_SG | NETIF_F_TSO;
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+	dev->net->hw_features |= NETIF_F_IP_CSUM;
+	dev->net->hw_features |= NETIF_F_IPV6_CSUM;
+	dev->net->hw_features |= NETIF_F_SG | NETIF_F_TSO;
+#endif
+
+	/* Enable checksum offload */
+	*tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
+	       AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp);
+
+	*tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP |
+	       AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
+
+	ax179_data->checksum |= AX_RX_CHECKSUM | AX_TX_CHECKSUM;
+
+	/* Configure RX control register => start operation */
+	*tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_START | AX_RX_CTL_AP |
+		 AX_RX_CTL_AMALL | AX_RX_CTL_AB;
+	if (NET_IP_ALIGN == 0)
+		*tmp16 |= AX_RX_CTL_IPE;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16);
+
+	*tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL |
+						AX_MONITOR_MODE_RWMP;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, tmp);
+
+	ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, tmp, 0);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_dbg(dev->net, "Monitor mode = 0x%02x\n", *tmp);
+#else
+		devdbg(dev, "Monitor mode = 0x%02x\n", *tmp);
+#endif
+	/* Configure default medium type => giga */
+	*tmp16 = AX_MEDIUM_RECEIVE_EN	 | AX_MEDIUM_TXFLOW_CTRLEN |
+		 AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_FULL_DUPLEX   |
+		 AX_MEDIUM_GIGAMODE;
+
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+			  2, 2, tmp16);
+
+	ax88179_led_setting(dev);
+
+	ax88179_EEE_setting(dev);
+
+	ax88179_Gether_setting(dev);
+
+	/* Restart autoneg */
+	mii_nway_restart(&dev->mii);
+
+	netif_carrier_off(dev->net);
+
+	kfree(buf);
+	printk(version);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_info(dev->net, "mtu %d\n", dev->net->mtu);
+#else
+		devinfo(dev, "mtu %d\n", dev->net->mtu);
+#endif
+	return 0;
+
+out:
+	kfree(buf);
+	return ret;
+
+}
+
+static void ax88179_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+	u16 tmp16 = 0;
+	u8 tmp8 = 0;
+	struct ax88179_data *ax179_data = (struct ax88179_data *) dev->data;
+
+	if (ax179_data) {
+		/* Configure RX control register => stop operation */
+		tmp16 = AX_RX_CTL_STOP;
+		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16);
+
+		tmp8 = 0x0;
+		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT,
+				  1, 1, &tmp8);
+
+		/* Power down ethernet PHY */
+		tmp16 = AX_PHYPWR_RSTCTL_BZ | AX_PHYPWR_RSTCTL_IPRL;
+		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
+				  2, 2, &tmp16);
+		msleep(200);
+	}
+}
+
+static void
+ax88179_rx_checksum(struct sk_buff *skb, u32 *pkt_hdr)
+{
+	skb->ip_summed = CHECKSUM_NONE;
+
+	/* checksum error bit is set */
+	if ((*pkt_hdr & AX_RXHDR_L3CSUM_ERR) ||
+	    (*pkt_hdr & AX_RXHDR_L4CSUM_ERR))
+		return;
+
+	/* It must be a TCP or UDP packet with a valid checksum */
+	if (((*pkt_hdr & AX_RXHDR_L4_TYPE_MASK) == AX_RXHDR_L4_TYPE_TCP) ||
+	    ((*pkt_hdr & AX_RXHDR_L4_TYPE_MASK) == AX_RXHDR_L4_TYPE_UDP))
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+}
+
+static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	struct sk_buff *ax_skb = NULL;
+	int pkt_cnt = 0;
+	u32 rx_hdr = 0;
+	u16 hdr_off = 0;
+	u32 *pkt_hdr = NULL;
+
+	skb_trim(skb, skb->len - 4);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+	memcpy(&rx_hdr, skb_tail_pointer(skb), sizeof(rx_hdr));
+#else
+	memcpy(&rx_hdr, skb->tail, sizeof(rx_hdr));
+#endif
+	le32_to_cpus(&rx_hdr);
+
+	pkt_cnt = (u16)rx_hdr;
+	hdr_off = (u16)(rx_hdr >> 16);
+	pkt_hdr = (u32 *)(skb->data + hdr_off);
+
+	while (pkt_cnt--) {
+		u16 pkt_len;
+
+		le32_to_cpus(pkt_hdr);
+		pkt_len = (*pkt_hdr >> 16) & 0x1fff;
+
+		/* Check CRC or runt packet */
+		if ((*pkt_hdr & AX_RXHDR_CRC_ERR) ||
+		    (*pkt_hdr & AX_RXHDR_DROP_ERR)) {
+			skb_pull(skb, (pkt_len + 7) & 0xFFF8);
+			pkt_hdr++;
+			continue;
+		}
+
+		if (pkt_cnt == 0) {			
+			skb->len = pkt_len;
+
+			/* Skip IP alignment psudo header */
+			if (NET_IP_ALIGN == 0)
+				skb_pull(skb, 2);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+			skb->tail = skb->data + skb->len;
+#else
+			skb_set_tail_pointer(skb, skb->len);
+#endif
+			skb->truesize = skb->len + sizeof(struct sk_buff);
+			ax88179_rx_checksum(skb, pkt_hdr);
+
+			return 1;
+		}
+
+#ifndef RX_SKB_COPY
+		ax_skb = skb_clone(skb, GFP_ATOMIC);
+#else
+		ax_skb = alloc_skb(pkt_len + NET_IP_ALIGN, GFP_ATOMIC);
+		skb_reserve(ax_skb, NET_IP_ALIGN);
+#endif
+
+		if (ax_skb) {
+#ifndef RX_SKB_COPY
+			ax_skb->len = pkt_len;
+	
+			/* Skip IP alignment psudo header */
+			if (NET_IP_ALIGN == 0)
+				skb_pull(ax_skb, 2);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+			ax_skb->tail = ax_skb->data + ax_skb->len;
+#else
+			skb_set_tail_pointer(ax_skb, ax_skb->len);
+#endif
+
+#else
+			skb_put(ax_skb, pkt_len);
+			memcpy(ax_skb->data, skb->data, pkt_len);
+
+			if (NET_IP_ALIGN == 0)
+				skb_pull(ax_skb, 2);
+#endif
+			ax_skb->truesize = ax_skb->len + sizeof(struct sk_buff);
+			ax88179_rx_checksum(ax_skb, pkt_hdr);
+			usbnet_skb_return(dev, ax_skb);
+		} else {
+			return 0;
+		}
+
+		skb_pull(skb, (pkt_len + 7) & 0xFFF8);
+		pkt_hdr++;
+	}
+	return 1;
+}
+
+static struct sk_buff *
+ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+	u32 tx_hdr1 = 0, tx_hdr2 = 0;
+	int frame_size = dev->maxpacket;
+	int mss = skb_shinfo(skb)->gso_size;
+	int headroom = 0;
+	int tailroom = 0;
+
+	tx_hdr1 = skb->len;
+	tx_hdr2 = mss;
+	if (((skb->len + 8) % frame_size) == 0)
+		tx_hdr2 |= 0x80008000;	/* Enable padding */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+	if (!dev->can_dma_sg && (dev->net->features & NETIF_F_SG) &&
+	    skb_linearize(skb))
+		return NULL;
+#else
+	if ((dev->net->features & NETIF_F_SG) && skb_linearize(skb))
+		return NULL;
+#endif
+
+	headroom = skb_headroom(skb);
+	tailroom = skb_tailroom(skb);
+
+	if ((headroom + tailroom) >= 8) {
+		if (headroom < 8) {
+			skb->data = memmove(skb->head + 8, skb->data, skb->len);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+			skb->tail = skb->data + skb->len;
+#else
+			skb_set_tail_pointer(skb, skb->len);
+#endif
+		}
+	} else {
+		struct sk_buff *skb2 = NULL;
+		skb2 = skb_copy_expand(skb, 8, 0, flags);
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		if (!skb)
+			return NULL;
+	}
+
+	skb_push(skb, 4);
+	cpu_to_le32s(&tx_hdr2);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+	memcpy(skb->data, &tx_hdr2, 4);
+#else
+	skb_copy_to_linear_data(skb, &tx_hdr2, 4);
+#endif
+
+	skb_push(skb, 4);
+	cpu_to_le32s(&tx_hdr1);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+	memcpy(skb->data, &tx_hdr1, 4);
+#else
+	skb_copy_to_linear_data(skb, &tx_hdr1, 4);
+#endif
+
+	return skb;
+}
+
+static int ax88179_link_reset(struct usbnet *dev)
+{
+	struct ax88179_data *data = (struct ax88179_data *)&dev->data;
+	u8 tmp[5] = {0}, link_sts = 0;
+	u16 mode = 0, tmp16 = 0, delay = HZ/10;
+	u32 tmp32 = 0x40000000;
+	unsigned long jtimeout = 0;
+
+	jtimeout = jiffies + delay;
+
+	while (tmp32 & 0x40000000) {
+		mode = 0;
+		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &mode);
+		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL,
+				  2, 2, &data->rxctl);
+
+		/* link up, check the usb device control TX FIFO full or empty*/
+		ax88179_read_cmd(dev, 0x81, 0x8c, 0, 4, &tmp32, 1);
+
+		if (time_after(jiffies, jtimeout))
+			return 0;
+	}
+
+	mode = AX_MEDIUM_RECEIVE_EN    | AX_MEDIUM_TXFLOW_CTRLEN |
+		   AX_MEDIUM_RXFLOW_CTRLEN;
+
+	ax88179_read_cmd(dev, AX_ACCESS_MAC, PHYSICAL_LINK_STATUS,
+			 1, 1, &link_sts, 0);
+	ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+			 GMII_PHY_PHYSR, 2, &tmp16, 1);
+
+	if (!(tmp16 & GMII_PHY_PHYSR_LINK))
+		return 0;
+	else if (GMII_PHY_PHYSR_GIGA == (tmp16 & GMII_PHY_PHYSR_SMASK)) {
+		mode |= AX_MEDIUM_GIGAMODE | AX_MEDIUM_EN_125MHZ;
+		if (dev->net->mtu > 1500)
+			mode |= AX_MEDIUM_JUMBO_EN;
+
+		if (link_sts & AX_USB_SS)
+			memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
+		else if (link_sts & AX_USB_HS)
+			memcpy(tmp, &AX88179_BULKIN_SIZE[1], 5);
+		else
+			memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
+	} else if (GMII_PHY_PHYSR_100 == (tmp16 & GMII_PHY_PHYSR_SMASK)) {
+		mode |= AX_MEDIUM_PS;	/* Bit 9 : PS */
+		if (link_sts & (AX_USB_SS | AX_USB_HS))
+			memcpy(tmp, &AX88179_BULKIN_SIZE[2], 5);
+		else
+			memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
+	} else
+		memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
+
+	if (bsize != -1) {
+		if (bsize > 24)
+			bsize = 24;
+
+		else if (bsize == 0) {
+			tmp[1] = 0;
+			tmp[2] = 0;
+		}
+
+		tmp[3] = (u8)bsize;
+	}
+
+	if (ifg != -1) {
+		if (ifg > 255)
+			ifg = 255;
+		tmp[4] = (u8)ifg;
+	}
+
+	/* RX bulk configuration */
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
+
+	if (tmp16 & GMII_PHY_PHYSR_FULL)
+		mode |= AX_MEDIUM_FULL_DUPLEX;	/* Bit 1 : FD */
+
+	dev->rx_urb_size = (1024 * (tmp[3] + 2));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_info(dev->net, "Write medium type: 0x%04x\n", mode);
+#else
+		devinfo(dev, "Write medium type: 0x%04x\n", mode);
+#endif
+	/* Configure default medium type => giga */
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+			  2, 2, &mode);
+	mii_check_media(&dev->mii, 1, 1);
+
+	return 0;
+}
+
+static int ax88179_reset(struct usbnet *dev)
+{
+	void *buf = NULL;
+	u16 *tmp16 = NULL;
+	u8 *tmp = NULL;
+	struct ax88179_data *ax179_data = (struct ax88179_data *) dev->data;
+	buf = kmalloc(6, GFP_KERNEL);
+
+	if (!buf) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+		netdev_err(dev->net, "Cannot allocate memory for buffer");
+#else
+		deverr(dev, "Cannot allocate memory for buffer");
+#endif
+		return -ENOMEM;
+	}
+
+	tmp16 = (u16 *)buf;
+	tmp = (u8 *)buf;
+
+	/* Power up ethernet PHY */
+	*tmp16 = 0;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
+	*tmp16 = AX_PHYPWR_RSTCTL_IPRL;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
+	msleep(200);
+
+	*tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp);
+	msleep(100);
+
+	/* Ethernet PHY Auto Detach*/
+	ax88179_AutoDetach(dev, 0);
+
+	/* Set the MAC address */
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
+			  ETH_ALEN, dev->net->dev_addr);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+	netdev_dbg(dev->net, "MAC [%02x-%02x-%02x-%02x-%02x-%02x]\n",
+	dev->net->dev_addr[0], dev->net->dev_addr[1],
+	dev->net->dev_addr[2], dev->net->dev_addr[3],
+	dev->net->dev_addr[4], dev->net->dev_addr[5]);
+#else
+	devdbg(dev, "MAC [%02x-%02x-%02x-%02x-%02x-%02x]\n",
+	dev->net->dev_addr[0], dev->net->dev_addr[1],
+	dev->net->dev_addr[2], dev->net->dev_addr[3],
+	dev->net->dev_addr[4], dev->net->dev_addr[5]);
+#endif
+
+	/* RX bulk configuration */
+	memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
+
+	dev->rx_urb_size = 1024 * 20;
+
+	tmp[0] = 0x34;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp);
+
+	tmp[0] = 0x52;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH,
+			  1, 1, tmp);
+
+	dev->net->features |= NETIF_F_IP_CSUM;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
+	dev->net->features |= NETIF_F_IPV6_CSUM;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+	if (usb_device_no_sg_constraint(dev->udev))
+		dev->can_dma_sg = 1;
+	dev->net->features |= NETIF_F_SG | NETIF_F_TSO;
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+	dev->net->hw_features |= NETIF_F_IP_CSUM;
+	dev->net->hw_features |= NETIF_F_IPV6_CSUM;
+	dev->net->hw_features |= NETIF_F_SG | NETIF_F_TSO;
+#endif
+
+	/* Enable checksum offload */
+	*tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
+	       AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp);
+
+	*tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP |
+	       AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
+
+	ax179_data->checksum |= AX_RX_CHECKSUM | AX_TX_CHECKSUM;
+
+	/* Configure RX control register => start operation */
+	*tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_START | AX_RX_CTL_AP |
+		 AX_RX_CTL_AMALL | AX_RX_CTL_AB;
+	if (NET_IP_ALIGN == 0)
+		*tmp16 |= AX_RX_CTL_IPE;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16);
+
+	*tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL |
+						AX_MONITOR_MODE_RWMP;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, tmp);
+
+	ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, tmp, 0);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+	netdev_dbg(dev->net, "Monitor mode = 0x%02x\n", *tmp);
+#else
+	devdbg(dev, "Monitor mode = 0x%02x\n", *tmp);
+#endif
+
+	/* Configure default medium type => giga */
+	*tmp16 = AX_MEDIUM_RECEIVE_EN	 | AX_MEDIUM_TXFLOW_CTRLEN |
+		 AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_FULL_DUPLEX   |
+		 AX_MEDIUM_GIGAMODE;
+
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+			  2, 2, tmp16);
+
+	ax88179_led_setting(dev);
+
+	ax88179_EEE_setting(dev);
+
+	ax88179_Gether_setting(dev);
+
+	/* Restart autoneg */
+	mii_nway_restart(&dev->mii);
+
+	netif_carrier_off(dev->net);
+
+	kfree(buf);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+	netdev_dbg(dev->net, "mtu %d\n", dev->net->mtu);
+#else
+	devdbg(dev, "mtu %d\n", dev->net->mtu);
+#endif
+
+	return 0;
+
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
+static int ax88179_stop(struct usbnet *dev)
+{
+	u16 tmp16 = 0;
+
+	ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+			 2, 2, &tmp16, 1);
+	tmp16 &= ~AX_MEDIUM_RECEIVE_EN;
+	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+			  2, 2, &tmp16);
+	return 0;
+}
+#endif
+
+static const struct driver_info ax88179_info = {
+	.description = "ASIX AX88179 USB 3.0 Gigabit Ethernet",
+	.bind	= ax88179_bind,
+	.unbind	= ax88179_unbind,
+	.status	= ax88179_status,
+	.link_reset = ax88179_link_reset,
+	.reset	= ax88179_reset,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
+	.stop	= ax88179_stop,
+	.flags	= FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS,
+#else
+	.flags	= FLAG_ETHER | FLAG_FRAMING_AX,
+#endif
+	.rx_fixup = ax88179_rx_fixup,
+	.tx_fixup = ax88179_tx_fixup,
+};
+
+
+static const struct driver_info ax88178a_info = {
+	.description = "ASIX AX88178A USB 2.0 Gigabit Ethernet",
+	.bind	= ax88179_bind,
+	.unbind	= ax88179_unbind,
+	.status	= ax88179_status,
+	.link_reset = ax88179_link_reset,
+	.reset	= ax88179_reset,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
+	.stop	= ax88179_stop,
+	.flags	= FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS,
+#else
+	.flags	= FLAG_ETHER | FLAG_FRAMING_AX,
+#endif
+	.rx_fixup = ax88179_rx_fixup,
+	.tx_fixup = ax88179_tx_fixup,
+};
+
+static const struct driver_info sitecom_info = {
+	.description = "Sitecom USB 3.0 to Gigabit Adapter",
+	.bind	= ax88179_bind,
+	.unbind	= ax88179_unbind,
+	.status	= ax88179_status,
+	.link_reset = ax88179_link_reset,
+	.reset	= ax88179_reset,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
+	.stop	= ax88179_stop,
+	.flags	= FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS,
+#else
+	.flags	= FLAG_ETHER | FLAG_FRAMING_AX,
+#endif
+	.rx_fixup = ax88179_rx_fixup,
+	.tx_fixup = ax88179_tx_fixup,
+};
+
+static const struct driver_info lenovo_info = {
+	.description = "ThinkPad OneLinkDock USB GigaLAN",
+	.bind	= ax88179_bind,
+	.unbind	= ax88179_unbind,
+	.status	= ax88179_status,
+	.link_reset = ax88179_link_reset,
+	.reset	= ax88179_reset,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
+	.stop	= ax88179_stop,
+	.flags	= FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS,
+#else
+	.flags	= FLAG_ETHER | FLAG_FRAMING_AX,
+#endif
+	.rx_fixup = ax88179_rx_fixup,
+	.tx_fixup = ax88179_tx_fixup,
+};
+
+static const struct driver_info toshiba_info = {
+	.description = "Toshiba USB 3.0 to Gigabit LAN Adapter",
+	.bind	= ax88179_bind,
+	.unbind	= ax88179_unbind,
+	.status	= ax88179_status,
+	.link_reset = ax88179_link_reset,
+	.reset	= ax88179_reset,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
+	.stop	= ax88179_stop,
+	.flags	= FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS,
+#else
+	.flags	= FLAG_ETHER | FLAG_FRAMING_AX,
+#endif
+	.rx_fixup = ax88179_rx_fixup,
+	.tx_fixup = ax88179_tx_fixup,
+};
+
+static const struct driver_info samsung_info = {
+	.description = "Samsung USB Ethernet Adapter",
+	.bind	= ax88179_bind,
+	.unbind = ax88179_unbind,
+	.status = ax88179_status,
+	.link_reset = ax88179_link_reset,
+	.reset	= ax88179_reset,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
+	.stop	= ax88179_stop,
+	.flags	= FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS,
+#else
+	.flags	= FLAG_ETHER | FLAG_FRAMING_AX,
+#endif
+	.rx_fixup = ax88179_rx_fixup,
+	.tx_fixup = ax88179_tx_fixup,
+};
+
+static const struct usb_device_id	products[] = {
+{
+	/* ASIX AX88179 10/100/1000 */
+	USB_DEVICE(0x0b95, 0x1790),
+	.driver_info = (unsigned long) &ax88179_info,
+}, {
+	/* ASIX AX88178A 10/100/1000 */
+	USB_DEVICE(0x0b95, 0x178a),
+	.driver_info = (unsigned long) &ax88178a_info,
+}, {
+	/* Sitecom USB 3.0 to Gigabit Adapter */
+	USB_DEVICE(0x0df6, 0x0072),
+	.driver_info = (unsigned long) &sitecom_info,
+}, {
+	/* ThinkPad OneLinkDock USB GigaLAN */
+	USB_DEVICE(0x17ef, 0x304b),
+	.driver_info = (unsigned long) &lenovo_info,
+}, {
+	/* Toshiba USB3.0 to Gigabit LAN Adapter */
+	USB_DEVICE(0x0930, 0x0a13),
+	.driver_info = (unsigned long) &toshiba_info,
+}, {
+	/* Samsung USB Ethernet Adapter */
+	USB_DEVICE(0x04e8, 0xa100),
+	.driver_info = (unsigned long) &samsung_info,
+},
+	{ },		/* END */
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver asix_driver = {
+	.name =		"ax88179_178a",
+	.id_table =	products,
+	.probe =	usbnet_probe,
+	.suspend =	ax88179_suspend,
+	.resume =	ax88179_resume,
+	.disconnect =	usbnet_disconnect,
+};
+
+
+static int __init asix_init(void)
+{
+	return usb_register(&asix_driver);
+}
+module_init(asix_init);
+
+static void __exit asix_exit(void)
+{
+	usb_deregister(&asix_driver);
+}
+module_exit(asix_exit);
+
+MODULE_AUTHOR("David Hollis");
+MODULE_DESCRIPTION("ASIX AX88179_178A based USB 2.0/3.0 Gigabit Ethernet Devices");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/net/usb/ax88179_178a.h b/drivers/net/usb/ax88179_178a.h
new file mode 100644
index 0000000..cbe4e9f
--- /dev/null
+++ b/drivers/net/usb/ax88179_178a.h
@@ -0,0 +1,365 @@
+#ifndef	__LINUX_USBNET_ASIX_H
+#define	__LINUX_USBNET_ASIX_H
+
+//#define RX_SKB_COPY
+
+#define AX88179_PHY_ID			0x03
+#define AX_MCAST_FILTER_SIZE		8
+#define AX_MAX_MCAST			64
+#define AX_EEPROM_LEN			0x40
+#define AX_RX_CHECKSUM			1
+#define AX_TX_CHECKSUM			2
+
+#define AX_BULKIN_24K			0x18;	/* 24k */
+
+#define AX_ACCESS_MAC			0x01
+#define AX_ACCESS_PHY			0x02
+#define AX_ACCESS_WAKEUP		0x03
+#define AX_ACCESS_EEPROM		0x04
+#define AX_ACCESS_EFUSE			0x05
+#define AX_RELOAD_EEPROM_EFUSE		0x06
+#define AX_WRITE_EFUSE_EN		0x09
+#define AX_WRITE_EFUSE_DIS		0x0A
+#define AX_ACCESS_MFAB			0x10
+
+#define PHYSICAL_LINK_STATUS		0x02
+	#define	AX_USB_SS		0x04
+	#define	AX_USB_HS		0x02
+	#define	AX_USB_FS		0x01
+
+#define GENERAL_STATUS			0x03
+/* Check AX88179 version. UA1:Bit2 = 0,  UA2:Bit2 = 1 */
+	#define	AX_SECLD		0x04
+
+
+
+#define AX_SROM_ADDR			0x07
+#define AX_SROM_CMD			0x0a
+	#define EEP_RD			0x04	/* EEprom read command */
+	#define EEP_WR			0x08	/* EEprom write command */
+	#define EEP_BUSY		0x10	/* EEprom access module busy */
+
+
+#define AX_SROM_DATA_LOW		0x08
+#define AX_SROM_DATA_HIGH		0x09
+
+#define AX_RX_CTL			0x0b
+	#define AX_RX_CTL_DROPCRCERR		0x0100 /* Drop CRC error packet */
+	#define AX_RX_CTL_IPE			0x0200 /* Enable IP header in receive buffer aligned on 32-bit aligment */
+	#define AX_RX_CTL_TXPADCRC		0x0400 /* checksum value in rx header 3 */
+	#define AX_RX_CTL_START			0x0080 /* Ethernet MAC start */
+	#define AX_RX_CTL_AP			0x0020 /* Accept physcial address from Multicast array */
+	#define AX_RX_CTL_AM			0x0010 /* Accetp Brocadcast frames*/
+	#define AX_RX_CTL_AB			0x0008 /* HW auto-added 8-bytes data when meet USB bulk in transfer boundary (1024/512/64)*/
+	#define AX_RX_CTL_HA8B			0x0004
+	#define AX_RX_CTL_AMALL			0x0002 /* Accetp all multicast frames */
+	#define AX_RX_CTL_PRO			0x0001 /* Promiscuous Mode */
+	#define AX_RX_CTL_STOP			0x0000 /* Stop MAC */
+
+#define AX_NODE_ID			0x10
+#define AX_MULTI_FILTER_ARRY		0x16
+
+#define AX_MEDIUM_STATUS_MODE			0x22
+	#define AX_MEDIUM_GIGAMODE	0x01
+	#define AX_MEDIUM_FULL_DUPLEX	0x02
+//	#define AX_MEDIUM_ALWAYS_ONE	0x04
+	#define AX_MEDIUM_EN_125MHZ	0x08
+	#define AX_MEDIUM_RXFLOW_CTRLEN	0x10
+	#define AX_MEDIUM_TXFLOW_CTRLEN	0x20
+	#define AX_MEDIUM_RECEIVE_EN	0x100
+	#define AX_MEDIUM_PS		0x200
+	#define AX_MEDIUM_JUMBO_EN	0x8040
+
+#define AX_MONITOR_MODE			0x24
+	#define AX_MONITOR_MODE_RWLC		0x02
+	#define AX_MONITOR_MODE_RWMP		0x04
+	#define AX_MONITOR_MODE_RWWF		0x08
+	#define AX_MONITOR_MODE_RW_FLAG		0x10
+	#define AX_MONITOR_MODE_PMEPOL		0x20
+	#define AX_MONITOR_MODE_PMETYPE		0x40
+
+#define AX_GPIO_CTRL			0x25
+	#define AX_GPIO_CTRL_GPIO3EN		0x80
+	#define AX_GPIO_CTRL_GPIO2EN		0x40
+	#define AX_GPIO_CTRL_GPIO1EN		0x20
+
+#define AX_PHYPWR_RSTCTL		0x26
+	#define AX_PHYPWR_RSTCTL_BZ		0x0010
+	#define AX_PHYPWR_RSTCTL_IPRL		0x0020
+	#define AX_PHYPWR_RSTCTL_AUTODETACH	0x1000
+
+#define AX_RX_BULKIN_QCTRL		0x2e
+	#define AX_RX_BULKIN_QCTRL_TIME		0x01
+	#define AX_RX_BULKIN_QCTRL_IFG		0x02
+	#define AX_RX_BULKIN_QCTRL_SIZE		0x04
+
+#define AX_RX_BULKIN_QTIMR_LOW		0x2f
+#define AX_RX_BULKIN_QTIMR_HIGH			0x30
+#define AX_RX_BULKIN_QSIZE			0x31
+#define AX_RX_BULKIN_QIFG			0x32
+
+#define AX_CLK_SELECT			0x33
+	#define AX_CLK_SELECT_BCS		0x01
+	#define AX_CLK_SELECT_ACS		0x02
+	#define AX_CLK_SELECT_ACSREQ		0x10
+	#define AX_CLK_SELECT_ULR		0x08
+
+#define AX_RXCOE_CTL			0x34
+	#define AX_RXCOE_IP			0x01
+	#define AX_RXCOE_TCP			0x02
+	#define AX_RXCOE_UDP			0x04
+	#define AX_RXCOE_ICMP			0x08
+	#define AX_RXCOE_IGMP			0x10
+	#define AX_RXCOE_TCPV6			0x20
+	#define AX_RXCOE_UDPV6			0x40
+	#define AX_RXCOE_ICMV6			0x80
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
+	#define AX_RXCOE_DEF_CSUM	(AX_RXCOE_IP	| AX_RXCOE_TCP  | \
+					 AX_RXCOE_UDP	| AX_RXCOE_ICMV6 | \
+					 AX_RXCOE_TCPV6	| AX_RXCOE_UDPV6)
+#else
+	#define AX_RXCOE_DEF_CSUM	(AX_RXCOE_IP	| AX_RXCOE_TCP | \
+					 AX_RXCOE_UDP)
+#endif
+
+#define AX_TXCOE_CTL			0x35
+	#define AX_TXCOE_IP			0x01
+	#define AX_TXCOE_TCP			0x02
+	#define AX_TXCOE_UDP			0x04
+	#define AX_TXCOE_ICMP			0x08
+	#define AX_TXCOE_IGMP			0x10
+	#define AX_TXCOE_TCPV6			0x20
+	#define AX_TXCOE_UDPV6			0x40
+	#define AX_TXCOE_ICMV6			0x80
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
+	#define AX_TXCOE_DEF_CSUM	(AX_TXCOE_TCP   | AX_TXCOE_UDP | \
+					 AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6)
+#else
+	#define AX_TXCOE_DEF_CSUM	(AX_TXCOE_TCP	| AX_TXCOE_UDP)
+#endif
+
+#define AX_PAUSE_WATERLVL_HIGH		0x54
+#define AX_PAUSE_WATERLVL_LOW		0x55
+
+
+#define AX_EEP_EFUSE_CORRECT		0x00
+#define AX88179_EEPROM_MAGIC			0x17900b95
+
+
+/*****************************************************************************/
+/* GMII register definitions */
+#define GMII_PHY_CONTROL			0x00	/* control reg */
+	/* Bit definitions: GMII Control */
+	#define GMII_CONTROL_RESET		0x8000	/* reset bit in control reg */
+	#define GMII_CONTROL_LOOPBACK		0x4000	/* loopback bit in control reg */
+	#define GMII_CONTROL_10MB		0x0000	/* 10 Mbit */
+	#define GMII_CONTROL_100MB		0x2000	/* 100Mbit */
+	#define GMII_CONTROL_1000MB		0x0040	/* 1000Mbit */
+	#define GMII_CONTROL_SPEED_BITS		0x2040	/* speed bit mask */
+	#define GMII_CONTROL_ENABLE_AUTO	0x1000	/* autonegotiate enable */
+	#define GMII_CONTROL_POWER_DOWN		0x0800
+	#define GMII_CONTROL_ISOLATE		0x0400	/* islolate bit */
+	#define GMII_CONTROL_START_AUTO		0x0200	/* restart autonegotiate */
+	#define GMII_CONTROL_FULL_DUPLEX	0x0100
+
+#define GMII_PHY_STATUS				0x01	/* status reg */
+	/* Bit definitions: GMII Status */
+	#define GMII_STATUS_100MB_MASK		0xE000	/* any of these indicate 100 Mbit */
+	#define GMII_STATUS_10MB_MASK		0x1800	/* either of these indicate 10 Mbit */
+	#define GMII_STATUS_AUTO_DONE		0x0020	/* auto negotiation complete */
+	#define GMII_STATUS_AUTO		0x0008	/* auto negotiation is available */
+	#define GMII_STATUS_LINK_UP		0x0004	/* link status bit */
+	#define GMII_STATUS_EXTENDED		0x0001	/* extended regs exist */
+	#define GMII_STATUS_100T4		0x8000	/* capable of 100BT4 */
+	#define GMII_STATUS_100TXFD		0x4000	/* capable of 100BTX full duplex */
+	#define GMII_STATUS_100TX		0x2000	/* capable of 100BTX */
+	#define GMII_STATUS_10TFD		0x1000	/* capable of 10BT full duplex */
+	#define GMII_STATUS_10T			0x0800	/* capable of 10BT */
+
+#define GMII_PHY_OUI				0x02	/* most of the OUI bits */
+#define GMII_PHY_MODEL				0x03	/* model/rev bits, and rest of OUI */
+#define GMII_PHY_ANAR				0x04	/* AN advertisement reg */
+	/* Bit definitions: Auto-Negotiation Advertisement */
+	#define GMII_ANAR_ASYM_PAUSE		0x0800	/* support asymetric pause */
+	#define GMII_ANAR_PAUSE			0x0400	/* support pause packets */
+	#define GMII_ANAR_100T4			0x0200	/* support 100BT4 */
+	#define GMII_ANAR_100TXFD		0x0100	/* support 100BTX full duplex */
+	#define GMII_ANAR_100TX			0x0080	/* support 100BTX half duplex */
+	#define GMII_ANAR_10TFD			0x0040	/* support 10BT full duplex */
+	#define GMII_ANAR_10T			0x0020	/* support 10BT half duplex */
+	#define GMII_SELECTOR_FIELD		0x001F	/* selector field. */
+
+#define GMII_PHY_ANLPAR				0x05	/* AN Link Partner */
+	/* Bit definitions: Auto-Negotiation Link Partner Ability */
+	#define GMII_ANLPAR_100T4		0x0200	/* support 100BT4 */
+	#define GMII_ANLPAR_100TXFD		0x0100	/* support 100BTX full duplex */
+	#define GMII_ANLPAR_100TX		0x0080	/* support 100BTX half duplex */
+	#define GMII_ANLPAR_10TFD		0x0040	/* support 10BT full duplex */
+	#define GMII_ANLPAR_10T			0x0020	/* support 10BT half duplex */
+	#define GMII_ANLPAR_PAUSE		0x0400	/* support pause packets */
+	#define GMII_ANLPAR_ASYM_PAUSE		0x0800	/* support asymetric pause */
+	#define GMII_ANLPAR_ACK			0x4000	/* means LCB was successfully rx'd */
+	#define GMII_SELECTOR_8023		0x0001;
+
+#define GMII_PHY_ANER				0x06	/* AN expansion reg */
+#define GMII_PHY_1000BT_CONTROL			0x09	/* control reg for 1000BT */
+#define GMII_PHY_1000BT_STATUS			0x0A	/* status reg for 1000BT */
+
+#define GMII_PHY_MACR				0x0D
+#define GMII_PHY_MAADR				0x0E
+
+#define GMII_PHY_PHYSR				0x11	/* PHY specific status register */
+	#define GMII_PHY_PHYSR_SMASK		0xc000
+	#define GMII_PHY_PHYSR_GIGA		0x8000
+	#define GMII_PHY_PHYSR_100		0x4000
+	#define GMII_PHY_PHYSR_FULL		0x2000
+	#define GMII_PHY_PHYSR_LINK		0x400
+
+/* Bit definitions: 1000BaseT AUX Control */
+#define GMII_1000_AUX_CTRL_MASTER_SLAVE		0x1000
+#define GMII_1000_AUX_CTRL_FD_CAPABLE		0x0200	/* full duplex capable */
+#define GMII_1000_AUX_CTRL_HD_CAPABLE		0x0100	/* half duplex capable */
+
+/* Bit definitions: 1000BaseT AUX Status */
+#define GMII_1000_AUX_STATUS_FD_CAPABLE		0x0800	/* full duplex capable */
+#define GMII_1000_AUX_STATUS_HD_CAPABLE		0x0400	/* half duplex capable */
+
+/*Cicada MII Registers */
+#define GMII_AUX_CTRL_STATUS			0x1C
+#define GMII_AUX_ANEG_CPLT			0x8000
+#define GMII_AUX_FDX				0x0020
+#define GMII_AUX_SPEED_1000			0x0010
+#define GMII_AUX_SPEED_100			0x0008
+
+#define GMII_LED_ACTIVE				0x1a
+	#define GMII_LED_ACTIVE_MASK		0xff8f
+	#define GMII_LED0_ACTIVE		(1 << 4)
+	#define GMII_LED1_ACTIVE		(1 << 5)
+	#define GMII_LED2_ACTIVE		(1 << 6)
+
+#define GMII_LED_LINK				0x1c
+	#define GMII_LED_LINK_MASK		0xf888
+	#define GMII_LED0_LINK_10		(1 << 0)
+	#define GMII_LED0_LINK_100		(1 << 1)
+	#define GMII_LED0_LINK_1000		(1 << 2)
+	#define GMII_LED1_LINK_10		(1 << 4)
+	#define GMII_LED1_LINK_100		(1 << 5)
+	#define GMII_LED1_LINK_1000		(1 << 6)
+	#define GMII_LED2_LINK_10		(1 << 8)
+	#define GMII_LED2_LINK_100		(1 << 9)
+	#define GMII_LED2_LINK_1000		(1 << 10)
+
+	#define	LED_VALID	(1 << 15) /* UA2 LED Setting */
+
+	#define	LED0_ACTIVE	(1 << 0)
+	#define	LED0_LINK_10	(1 << 1)
+	#define	LED0_LINK_100	(1 << 2)
+	#define	LED0_LINK_1000	(1 << 3)
+	#define	LED0_FD		(1 << 4)
+	#define LED0_USB3_MASK	0x001f
+
+	#define	LED1_ACTIVE	(1 << 5)
+	#define	LED1_LINK_10	(1 << 6)
+	#define	LED1_LINK_100	(1 << 7)
+	#define	LED1_LINK_1000	(1 << 8)
+	#define	LED1_FD		(1 << 9)
+	#define LED1_USB3_MASK	0x03e0
+
+	#define	LED2_ACTIVE	(1 << 10)
+	#define	LED2_LINK_1000	(1 << 13)
+	#define	LED2_LINK_100	(1 << 12)
+	#define	LED2_LINK_10	(1 << 11)
+	#define	LED2_FD		(1 << 14)
+	#define LED2_USB3_MASK	0x7c00
+
+#define GMII_PHYPAGE				0x1e
+
+#define GMII_PHY_PAGE_SELECT			0x1f
+	#define GMII_PHY_PAGE_SELECT_EXT	0x0007
+	#define GMII_PHY_PAGE_SELECT_PAGE0	0X0000
+	#define GMII_PHY_PAGE_SELECT_PAGE1	0X0001
+	#define GMII_PHY_PAGE_SELECT_PAGE2	0X0002
+	#define GMII_PHY_PAGE_SELECT_PAGE3	0X0003
+	#define GMII_PHY_PAGE_SELECT_PAGE4	0X0004
+	#define GMII_PHY_PAGE_SELECT_PAGE5	0X0005
+	#define GMII_PHY_PAGE_SELECT_PAGE6	0X0006
+
+/******************************************************************************/
+
+struct ax88179_data {
+	u16 rxctl;
+	u8  checksum;
+} __attribute__ ((packed));
+
+struct ax88179_async_handle {
+  	struct usb_ctrlrequest *req;
+  	u8 m_filter[8];
+  	u16 rxctl;
+} __attribute__ ((packed));
+
+struct ax88179_int_data {
+	__le16 res1;
+#define AX_INT_PPLS_LINK	(1 << 0)
+#define AX_INT_SPLS_LINK	(1 << 1)
+#define AX_INT_CABOFF_UNPLUG	(1 << 7)
+	u8 link;
+	__le16 res2;
+	u8 status;
+	__le16 res3;
+} __attribute__ ((packed));
+
+#define AX_RXHDR_L4_ERR		(1 << 8)
+#define AX_RXHDR_L3_ERR		(1 << 9)
+
+
+#define AX_RXHDR_L4_TYPE_ICMP		2
+#define AX_RXHDR_L4_TYPE_IGMP		3
+#define AX_RXHDR_L4_TYPE_TCMPV6		5
+
+#define AX_RXHDR_L3_TYPE_IP		1
+#define AX_RXHDR_L3_TYPE_IPV6		2
+
+#define AX_RXHDR_L4_TYPE_MASK			0x1c
+#define AX_RXHDR_L4_TYPE_UDP			4
+#define AX_RXHDR_L4_TYPE_TCP			16
+#define AX_RXHDR_L3CSUM_ERR			2
+#define AX_RXHDR_L4CSUM_ERR			1
+#define AX_RXHDR_CRC_ERR			0x20000000
+#define AX_RXHDR_MII_ERR			0x40000000
+#define AX_RXHDR_DROP_ERR			0x80000000
+#if 0
+struct ax88179_rx_pkt_header {
+
+	u8	l4_csum_err:1,
+		l3_csum_err:1,
+		l4_type:3,
+		l3_type:2,
+		ce:1;
+
+	u8	vlan_ind:3,
+		rx_ok:1,
+		pri:3,
+		bmc:1;
+
+	u16	len:13,
+		crc:1,
+		mii:1,
+		drop:1;
+
+} __attribute__ ((packed));
+#endif
+static struct {unsigned char ctrl, timer_l, timer_h, size, ifg; }
+AX88179_BULKIN_SIZE[] =	{
+	{7, 0x4f, 0,	0x12, 0xff},
+	{7, 0x20, 3,	0x16, 0xff},
+	{7, 0xae, 7,	0x18, 0xff},
+	{7, 0xcc, 0x4c, 0x18, 8},
+};
+
+static int ax88179_reset(struct usbnet *dev);
+static int ax88179_link_reset(struct usbnet *dev);
+static int ax88179_AutoDetach(struct usbnet *dev, int in_pm);
+
+#endif /* __LINUX_USBNET_ASIX_H */
+
-- 
1.9.1

